/*这段代码使用了sys/sem.h头文件中的信号量相关函数和结构体。

union semun定义了一个联合体，用于设置信号量的初始值。
create_sem函数通过调用ftok生成一个唯一的key，并使用该key创建一个信号量集合，其中包含一个信号量。返回创建的信号量的标识符。
init_sem函数初始化指定标识符的信号量为给定的初始值。
del_sem函数删除指定标识符的信号量。
sem_p函数执行P操作（减操作），将信号量的值减1。
sem_v函数执行V操作（加操作），将信号量的值加1。

这些函数提供了对信号量的基本操作，用于实现进程间的同步和互斥。P操作和V操作是常用的信号量操作，用于控制进程的访问和资源的分配。*/

#include <sys/sem.h>

union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

// 创建一个信号量，使用字符ch生成唯一的key
int create_sem(char ch){
    int sem_id;
    key_t sem_key;

    sem_key = ftok(".", ch);    // 生成唯一的key
    if ((sem_id = semget(sem_key, 1, 0666|IPC_CREAT)) == -1){    // 创建信号量集合，其中包含一个信号量
        perror("sem get");
        exit(-1);
    }

    return sem_id;
}

// 初始化信号量为指定的初始值
int init_sem(int sem_id, int init_value){
    union semun sem_union;
    sem_union.val = init_value;
    if (semctl(sem_id, 0, SETVAL, sem_union) == -1){    // 设置信号量的值
        perror("sem init");
        exit(-1);
    }
    return 0;
}

// 删除信号量
int del_sem(int sem_id){
    union semun sem_union;
    if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1){    // 删除信号量
        perror("sem delete");
        exit(-1);
    }
    return 0;
}

// 对信号量进行P操作（减操作）
int sem_p(int sem_id){
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;    // 操作信号量集合中的第一个信号量
    sem_buf.sem_op = -1;    // 减1
    sem_buf.sem_flg = SEM_UNDO;

    if (semop(sem_id, &sem_buf, 1) == -1){    // 执行P操作
        perror("sem p");
        exit(-1);
    }   
    return 0;
}

// 对信号量进行V操作（加操作）
int sem_v(int sem_id){
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;    // 操作信号量集合中的第一个信号量
    sem_buf.sem_op = 1;     // 加1
    sem_buf.sem_flg = SEM_UNDO;

    if (semop(sem_id, &sem_buf, 1) == -1){    // 执行V操作
        perror("sem p");
        exit(-1);
    }   
    return 0;
}
